বাংলা

টাইপস্ক্রিপ্ট জেনেরিকসের একটি সম্পূর্ণ গাইড, যেখানে এর সিনট্যাক্স, সুবিধা, উন্নত ব্যবহার এবং বিশ্বব্যাপী সফটওয়্যার ডেভেলপমেন্টে জটিল ডেটা টাইপ পরিচালনার সেরা অনুশীলনগুলি আলোচনা করা হয়েছে।

টাইপস্ক্রিপ্ট জেনেরিকস: শক্তিশালী অ্যাপ্লিকেশনের জন্য জটিল ডেটা টাইপ আয়ত্ত করা

টাইপস্ক্রিপ্ট, যা জাভাস্ক্রিপ্টের একটি সুপারসেট, ডেভেলপারদের স্ট্যাটিক টাইপিংয়ের মাধ্যমে আরও শক্তিশালী এবং রক্ষণাবেক্ষণযোগ্য কোড লিখতে সাহায্য করে। এর সবচেয়ে শক্তিশালী বৈশিষ্ট্যগুলির মধ্যে একটি হলো জেনেরিকস, যা আপনাকে বিভিন্ন ডেটা টাইপের সাথে কাজ করতে পারে এমন কোড লিখতে দেয় এবং একই সাথে টাইপ সেফটি বজায় রাখে। এই গাইডটি টাইপস্ক্রিপ্ট জেনেরিকসের একটি বিশদ আলোচনা প্রদান করে, যেখানে গ্লোবাল সফটওয়্যার ডেভেলপমেন্টের প্রেক্ষাপটে জটিল ডেটা টাইপের উপর এর প্রয়োগের উপর জোর দেওয়া হয়েছে।

জেনেরিকস কী?

জেনেরিকস পুনঃব্যবহারযোগ্য কোড লেখার একটি উপায় প্রদান করে যা বিভিন্ন টাইপের সাথে কাজ করতে পারে। আপনি যে প্রতিটি টাইপ সমর্থন করতে চান তার জন্য আলাদা ফাংশন বা ক্লাস লেখার পরিবর্তে, আপনি একটি একক ফাংশন বা ক্লাস লিখতে পারেন যা টাইপ প্যারামিটার ব্যবহার করে। এই টাইপ প্যারামিটারগুলি আসল টাইপের জন্য প্লেসহোল্ডার হিসাবে কাজ করে যা ফাংশন বা ক্লাস কল বা ইনস্ট্যানশিয়েট করার সময় ব্যবহৃত হবে। এটি বিশেষত জটিল ডেটা স্ট্রাকচারের সাথে কাজ করার সময় উপযোগী, যেখানে সেই স্ট্রাকচারের মধ্যে ডেটার টাইপ ভিন্ন হতে পারে।

জেনেরিকস ব্যবহারের সুবিধা

জেনেরিকসের বেসিক সিনট্যাক্স

জেনেরিকসের বেসিক সিনট্যাক্সে অ্যাঙ্গেল ব্র্যাকেট (< >) ব্যবহার করে টাইপ প্যারামিটার ঘোষণা করা হয়। এই টাইপ প্যারামিটারগুলির নাম সাধারণত T, K, V ইত্যাদি হয়, তবে আপনি যেকোনো বৈধ আইডেন্টিফায়ার ব্যবহার করতে পারেন। এখানে একটি জেনেরিক ফাংশনের একটি সহজ উদাহরণ দেওয়া হলো:


function identity<T>(arg: T): T {
  return arg;
}

let myString: string = identity<string>("hello");
let myNumber: number = identity<number>(123);
let myBoolean: boolean = identity<boolean>(true);

console.log(myString); // Output: hello
console.log(myNumber); // Output: 123
console.log(myBoolean); // Output: true

এই উদাহরণে, <T> একটি টাইপ প্যারামিটার ঘোষণা করে যার নাম Tidentity ফাংশনটি T টাইপের একটি আর্গুমেন্ট নেয় এবং T টাইপের একটি ভ্যালু রিটার্ন করে। ফাংশনটি কল করার সময়, আপনি স্পষ্টভাবে টাইপ প্যারামিটার উল্লেখ করতে পারেন (যেমন, identity<string>) অথবা টাইপস্ক্রিপ্টকে আর্গুমেন্ট টাইপের উপর ভিত্তি করে এটি অনুমান করতে দিতে পারেন।

জটিল ডেটা টাইপ নিয়ে কাজ করা

অ্যারে, অবজেক্ট এবং ইন্টারফেসের মতো জটিল ডেটা টাইপের সাথে কাজ করার সময় জেনেরিকস বিশেষভাবে মূল্যবান হয়ে ওঠে। আসুন কিছু সাধারণ পরিস্থিতি অন্বেষণ করি:

জেনেরিক অ্যারে

আপনি বিভিন্ন টাইপের অ্যারের সাথে কাজ করতে পারে এমন ফাংশন বা ক্লাস তৈরি করতে জেনেরিকস ব্যবহার করতে পারেন:


function arrayToString<T>(arr: T[]): string {
  return arr.join(", ");
}

let numberArray: number[] = [1, 2, 3, 4, 5];
let stringArray: string[] = ["apple", "banana", "cherry"];

console.log(arrayToString(numberArray)); // Output: 1, 2, 3, 4, 5
console.log(arrayToString(stringArray)); // Output: apple, banana, cherry

এখানে, arrayToString ফাংশনটি T[] টাইপের একটি অ্যারে নেয় এবং অ্যারের একটি স্ট্রিং রিপ্রেজেন্টেশন রিটার্ন করে। এই ফাংশনটি যেকোনো টাইপের অ্যারের সাথে কাজ করে, যা এটিকে অত্যন্ত পুনঃব্যবহারযোগ্য করে তোলে।

জেনেরিক অবজেক্ট

বিভিন্ন আকারের অবজেক্টের সাথে কাজ করে এমন ফাংশন বা ক্লাস সংজ্ঞায়িত করতেও জেনেরিকস ব্যবহার করা যেতে পারে:


interface Person {
  name: string;
  age: number;
  country: string; // Added country for global context
}

interface Product {
  id: number;
  name: string;
  price: number;
  currency: string; // Added currency for global context
}

function displayInfo<T extends { name: string }>(item: T): void {
  console.log(`Name: ${item.name}`);
}

let person: Person = { name: "Alice", age: 30, country: "USA" };
let product: Product = { id: 1, name: "Laptop", price: 1200, currency: "USD" };

displayInfo(person); // Output: Name: Alice
displayInfo(product); // Output: Name: Laptop

এই উদাহরণে, displayInfo ফাংশনটি T টাইপের একটি অবজেক্ট নেয় যার অবশ্যই স্ট্রিং টাইপের একটি name প্রপার্টি থাকতে হবে। extends { name: string } ক্লজটি একটি কনস্ট্রেইন্ট, যা টাইপ প্যারামিটার T-এর জন্য সর্বনিম্ন প্রয়োজনীয়তা নির্দিষ্ট করে। এটি নিশ্চিত করে যে ফাংশনটি নিরাপদে name প্রপার্টি অ্যাক্সেস করতে পারে।

জেনেরিকসের উন্নত ব্যবহার

টাইপস্ক্রিপ্ট জেনেরিকস আরও উন্নত বৈশিষ্ট্য প্রদান করে যা আপনাকে আরও নমনীয় এবং শক্তিশালী কোড তৈরি করতে দেয়। আসুন এই বৈশিষ্ট্যগুলির কিছু অন্বেষণ করি:

একাধিক টাইপ প্যারামিটার

আপনি একাধিক টাইপ প্যারামিটার সহ ফাংশন বা ক্লাস সংজ্ঞায়িত করতে পারেন:


function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

interface Name {
  firstName: string;
}

interface Age {
  age: number;
}

const person: Name = { firstName: "Bob" };
const details: Age = { age: 42 };

const merged = merge(person, details);
console.log(merged.firstName); // Output: Bob
console.log(merged.age); // Output: 42

merge ফাংশনটি T এবং U টাইপের দুটি অবজেক্ট নেয় এবং একটি নতুন অবজেক্ট রিটার্ন করে যাতে উভয় অবজেক্টের প্রপার্টি থাকে। এটি বিভিন্ন উৎস থেকে ডেটা একত্রিত করার একটি শক্তিশালী উপায়।

জেনেরিক কনস্ট্রেইন্টস

আগে যেমন দেখানো হয়েছে, কনস্ট্রেইন্টস আপনাকে জেনেরিক টাইপ প্যারামিটারের সাথে ব্যবহার করা যেতে পারে এমন টাইপগুলিকে সীমাবদ্ধ করতে দেয়। এটি নিশ্চিত করে যে জেনেরিক কোড নির্দিষ্ট টাইপগুলিতে নিরাপদে কাজ করতে পারে।


interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

loggingIdentity([1, 2, 3]); // Output: 3
loggingIdentity("hello"); // Output: 5
// loggingIdentity(123); // Error: Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.

loggingIdentity ফাংশনটি T টাইপের একটি আর্গুমেন্ট নেয় যার অবশ্যই নম্বর টাইপের একটি length প্রপার্টি থাকতে হবে। এটি নিশ্চিত করে যে ফাংশনটি নিরাপদে length প্রপার্টি অ্যাক্সেস করতে পারে।

জেনেরিক ক্লাস

জেনেরিকস ক্লাসগুলির সাথেও ব্যবহার করা যেতে পারে:


class DataStorage<T> {
  private data: T[] = [];

  addItem(item: T) {
    this.data.push(item);
  }

  removeItem(item: T) {
    this.data = this.data.filter(d => d !== item);
  }

  getItems(): T[] {
    return [...this.data];
  }
}

const textStorage = new DataStorage<string>();
textStorage.addItem("apple");
textStorage.addItem("banana");
textStorage.removeItem("apple");
console.log(textStorage.getItems()); // Output: [ 'banana' ]

const numberStorage = new DataStorage<number>();
numberStorage.addItem(1);
numberStorage.addItem(2);
numberStorage.removeItem(1);
console.log(numberStorage.getItems()); // Output: [ 2 ]

DataStorage ক্লাসটি যেকোনো T টাইপের ডেটা সংরক্ষণ করতে পারে। এটি আপনাকে পুনঃব্যবহারযোগ্য ডেটা স্ট্রাকচার তৈরি করতে দেয় যা টাইপ-সেফ।

জেনেরিক ইন্টারফেস

জেনেরিক ইন্টারফেসগুলি বিভিন্ন টাইপের সাথে কাজ করতে পারে এমন চুক্তি সংজ্ঞায়িত করার জন্য উপযোগী। উদাহরণস্বরূপ:


interface Result<T, E> {
  success: boolean;
  data?: T;
  error?: E;
}

interface User {
  id: number;
  username: string;
  email: string;
}

interface ErrorMessage {
  code: number;
  message: string;
}

function fetchUser(id: number): Result<User, ErrorMessage> {
  if (id === 1) {
    return { success: true, data: { id: 1, username: "john.doe", email: "john.doe@example.com" } };
  } else {
    return { success: false, error: { code: 404, message: "User not found" } };
  }
}

const userResult = fetchUser(1);
if (userResult.success) {
  console.log(userResult.data.username);
} else {
  console.log(userResult.error.message);
}

Result ইন্টারফেসটি একটি অপারেশনের ফলাফল উপস্থাপনের জন্য একটি জেনেরিক কাঠামো সংজ্ঞায়িত করে। এটি হয় T টাইপের ডেটা অথবা E টাইপের একটি ত্রুটি ধারণ করতে পারে। এটি অ্যাসিঙ্ক্রোনাস অপারেশন বা ব্যর্থ হতে পারে এমন অপারেশনগুলি পরিচালনা করার জন্য একটি সাধারণ প্যাটার্ন।

ইউটিলিটি টাইপস এবং জেনেরিকস

টাইপস্ক্রিপ্ট বেশ কিছু বিল্ট-ইন ইউটিলিটি টাইপ সরবরাহ করে যা জেনেরিকসের সাথে ভালভাবে কাজ করে। এই ইউটিলিটি টাইপগুলি আপনাকে শক্তিশালী উপায়ে টাইপগুলিকে রূপান্তর এবং ম্যানিপুলেট করতে সহায়তা করতে পারে।

Partial<T>

Partial<T> টাইপ T-এর সমস্ত প্রপার্টিকে ঐচ্ছিক করে তোলে:


interface Person {
  name: string;
  age: number;
}

type PartialPerson = Partial<Person>;

const partialPerson: PartialPerson = { name: "Alice" }; // Valid

Readonly<T>

Readonly<T> টাইপ T-এর সমস্ত প্রপার্টিকে রিডঅনলি করে তোলে:


interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly<Person>;

const readonlyPerson: ReadonlyPerson = { name: "Bob", age: 42 };
// readonlyPerson.age = 43; // Error: Cannot assign to 'age' because it is a read-only property.

Pick<T, K>

Pick<T, K> টাইপ T থেকে K প্রপার্টির একটি সেট নির্বাচন করে:


interface Person {
  name: string;
  age: number;
  email: string;
}

type NameAndAge = Pick<Person, "name" | "age">;

const nameAndAge: NameAndAge = { name: "Charlie", age: 28 };

Omit<T, K>

Omit<T, K> টাইপ T থেকে K প্রপার্টির একটি সেট সরিয়ে দেয়:


interface Person {
  name: string;
  age: number;
  email: string;
}

type PersonWithoutEmail = Omit<Person, "email">;

const personWithoutEmail: PersonWithoutEmail = { name: "David", age: 35 };

Record<K, T>

Record<K, T> একটি টাইপ তৈরি করে যার কী K এবং ভ্যালু T টাইপের:


type CountryCodes = "US" | "CA" | "UK" | "DE" | "FR" | "JP" | "CN" | "IN" | "BR" | "AU"; // Expanded list for global context
type Currency = "USD" | "CAD" | "GBP" | "EUR" | "JPY" | "CNY" | "INR" | "BRL" | "AUD"; // Expanded list for global context

type CurrencyMap = Record<CountryCodes, Currency>;

const currencyMap: CurrencyMap = {
  "US": "USD",
  "CA": "CAD",
  "UK": "GBP",
  "DE": "EUR",
  "FR": "EUR",
  "JP": "JPY",
  "CN": "CNY",
  "IN": "INR",
  "BR": "BRL",
  "AU": "AUD",
};

ম্যাপড টাইপস

ম্যাপড টাইপস আপনাকে বিদ্যমান টাইপগুলির প্রপার্টিগুলির উপর পুনরাবৃত্তি করে সেগুলিকে রূপান্তর করতে দেয়। এটি বিদ্যমান টাইপের উপর ভিত্তি করে নতুন টাইপ তৈরি করার একটি শক্তিশালী উপায়। উদাহরণস্বরূপ, আপনি এমন একটি টাইপ তৈরি করতে পারেন যা অন্য টাইপের সমস্ত প্রপার্টিকে রিডঅনলি করে তোলে:


interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K];
};

const readonlyPerson: ReadonlyPerson = { name: "Eve", age: 25 };
// readonlyPerson.age = 26; // Error: Cannot assign to 'age' because it is a read-only property.

এই উদাহরণে, [K in keyof Person] Person ইন্টারফেসের সমস্ত কীগুলির উপর পুনরাবৃত্তি করে এবং Person[K] প্রতিটি প্রপার্টির টাইপ অ্যাক্সেস করে। readonly কীওয়ার্ড প্রতিটি প্রপার্টিকে রিডঅনলি করে তোলে।

কন্ডিশনাল টাইপস

কন্ডিশনাল টাইপস আপনাকে শর্তের উপর ভিত্তি করে টাইপ সংজ্ঞায়িত করতে দেয়। এটি বিভিন্ন পরিস্থিতিতে মানিয়ে নিতে পারে এমন টাইপ তৈরি করার একটি শক্তিশালী উপায়।


type NonNullable<T> = T extends null | undefined ? never : T;

type MaybeString = string | null | undefined;
type StringType = NonNullable<MaybeString>; // string

function getValue<T>(value: T): NonNullable<T> {
  if (value == null) { // Handles both null and undefined
    throw new Error("Value cannot be null or undefined");
  }
  return value as NonNullable<T>;
}

try {
  const validValue = getValue("hello");
  console.log(validValue.toUpperCase()); // Output: HELLO

  const invalidValue = getValue(null); // This will throw an error
  console.log(invalidValue); // This line will not be reached
} catch (error: any) {
  console.error(error.message); // Output: Value cannot be null or undefined
}

এই উদাহরণে, NonNullable<T> টাইপটি পরীক্ষা করে যে T null বা undefined কিনা। যদি তা হয়, তবে এটি never রিটার্ন করে, যার অর্থ টাইপটি অনুমোদিত নয়। অন্যথায়, এটি T রিটার্ন করে। এটি আপনাকে এমন টাইপ তৈরি করতে দেয় যা নন-নালেবল হওয়ার নিশ্চয়তা দেয়।

জেনেরিকস ব্যবহারের সেরা অনুশীলন

জেনেরিকস ব্যবহার করার সময় মনে রাখার জন্য এখানে কিছু সেরা অনুশীলন রয়েছে:

গ্লোবাল কনটেক্সটে উদাহরণ

আসুন কিছু উদাহরণ বিবেচনা করি যেখানে গ্লোবাল কনটেক্সটে জেনেরিকস ব্যবহার করা যেতে পারে:

মুদ্রা রূপান্তর


interface ConversionRate {
  rate: number;
  fromCurrency: string;
  toCurrency: string;
}

function convertCurrency<T extends ConversionRate>(amount: number, rate: T): number {
  return amount * rate.rate;
}

const usdToEurRate: ConversionRate = { rate: 0.85, fromCurrency: "USD", toCurrency: "EUR" };
const amountInUSD = 100;
const amountInEUR = convertCurrency(amountInUSD, usdToEurRate);
console.log(`${amountInUSD} USD is equal to ${amountInEUR} EUR`); // Output: 100 USD is equal to 85 EUR

তারিখ ফরম্যাটিং


interface DateFormatOptions {
  locale: string;
  options: Intl.DateTimeFormatOptions;
}

function formatDate<T extends DateFormatOptions>(date: Date, format: T): string {
  return date.toLocaleDateString(format.locale, format.options);
}

const currentDate = new Date();

const usDateFormat: DateFormatOptions = { locale: "en-US", options: { year: 'numeric', month: 'long', day: 'numeric' } };
const germanDateFormat: DateFormatOptions = { locale: "de-DE", options: { year: 'numeric', month: 'long', day: 'numeric' } };
const japaneseDateFormat: DateFormatOptions = { locale: "ja-JP", options: { year: 'numeric', month: 'long', day: 'numeric' } };

console.log("US Date: " + formatDate(currentDate, usDateFormat));
console.log("German Date: " + formatDate(currentDate, germanDateFormat));
console.log("Japanese Date: " + formatDate(currentDate, japaneseDateFormat));

অনুবাদ পরিষেবা


interface Translation {
  [key: string]: string; // Allows for dynamic language keys
}

interface LanguageData<T extends Translation> {
  languageCode: string;
  translations: T;
}

const englishTranslations: Translation = {
  "hello": "Hello",
  "goodbye": "Goodbye",
  "welcome": "Welcome to our website!"
};

const spanishTranslations: Translation = {
  "hello": "Hola",
  "goodbye": "Adiós",
  "welcome": "¡Bienvenido a nuestro sitio web!"
};

const frenchTranslations: Translation = {
  "hello": "Bonjour",
  "goodbye": "Au revoir",
  "welcome": "Bienvenue sur notre site web !"
};


const languageData: LanguageData<typeof englishTranslations>[] = [
  {languageCode: "en", translations: englishTranslations },
  {languageCode: "es", translations: spanishTranslations },
  {languageCode: "fr", translations: frenchTranslations}
];

function translate<T extends Translation>(key: string, languageCode: string, languageData: LanguageData<T>[]): string {
  const lang = languageData.find(lang => lang.languageCode === languageCode);
  if (!lang) {
    return `Translation for ${key} in ${languageCode} not found.`;
  }
  return lang.translations[key] || `Translation for ${key} not found.`;
}

console.log(translate("hello", "en", languageData)); // Output: Hello
console.log(translate("hello", "es", languageData)); // Output: Hola
console.log(translate("welcome", "fr", languageData)); // Output: Bienvenue sur notre site web !
console.log(translate("missingKey", "de", languageData)); // Output: Translation for missingKey in de not found.

উপসংহার

টাইপস্ক্রিপ্ট জেনেরিকস পুনঃব্যবহারযোগ্য, টাইপ-সেফ কোড লেখার জন্য একটি শক্তিশালী টুল যা জটিল ডেটা টাইপের সাথে কাজ করতে পারে। জেনেরিকসের বেসিক সিনট্যাক্স, উন্নত বৈশিষ্ট্য এবং সেরা অনুশীলনগুলি বোঝার মাধ্যমে, আপনি আপনার টাইপস্ক্রিপ্ট অ্যাপ্লিকেশনগুলির গুণমান এবং রক্ষণাবেক্ষণযোগ্যতা উল্লেখযোগ্যভাবে উন্নত করতে পারেন। একটি বিশ্বব্যাপী দর্শকদের জন্য অ্যাপ্লিকেশন তৈরি করার সময়, জেনেরিকস আপনাকে বিভিন্ন ডেটা ফরম্যাট এবং সাংস্কৃতিক প্রথাগুলি পরিচালনা করতে সহায়তা করতে পারে, যা প্রত্যেকের জন্য একটি মসৃণ ব্যবহারকারীর অভিজ্ঞতা নিশ্চিত করে।